package com.wanban.network

import android.text.TextUtils
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope

import com.google.gson.Gson
import com.wanban.tools.*
import kotlinx.coroutines.*
import java.lang.Exception
import java.util.*

open class BaseViewModel : ViewModel() {

    /**
     * 获取UTC的时间戳
     */
    fun getSecondTimestamp(): Long {
        val zone = TimeZone.getTimeZone("UTC+8")
        val cal = Calendar.getInstance(zone)
        return cal.timeInMillis
    }

    fun getAppId(): String {
        return "100180001"
    }

    fun getAppKey(): String {
        return "18a4b60ce431ae2e4e9f33da2cf6cf4c"
    }

    fun getExtra(): String {
        return "notice"
    }




    suspend fun getToken() = withContext(Dispatchers.IO) {
        try {
            val appId = getAppId()
            val appKey = getAppKey()
            val timestamp = getSecondTimestamp()
            val sign = MD5Utils.getMD5String(
                "b277322e1ca4c4c5ef51242c900726c2",
                appId,
                appKey,
                timestamp.toString(),
                getExtra()
            )
            val request = CheckAppRequest(appId, timestamp, sign)
            val result = RetrofitUtils.instance.getApi(Api::class.java).checkApp(request)
            if (result == null || TextUtils.isEmpty(result.body) || TextUtils.isEmpty(result.ticket)) {
                return@withContext null
            }
            // 用rsa的私钥去解密ticket，获得aes的秘钥
            val aesKey = EncryptionUtils.rsaDecrypt(result.ticket)
            if (TextUtils.isEmpty(aesKey)) {
                return@withContext null
            }
            val jsonBody = EncryptionUtils.aesDecrypt(result.body, aesKey)
            val gson = Gson()
            val checkResponse = gson.fromJson(jsonBody, CheckResponse::class.java)
            if (TextUtils.isEmpty(checkResponse.data)) {
                return@withContext null
            }
            // 保存本地
            val updateTime = System.currentTimeMillis() + checkResponse.duration * 1000
            SPUtil.instance.tokenExpireTime = updateTime
            if (checkResponse.data != null) {
                SPUtil.instance.token = checkResponse.data!!
            }
            SPUtil.instance.tf = checkResponse.tf
            return@withContext checkResponse.data
        } catch (e: Exception) {
            e.printStackTrace()
            return@withContext null
        }
    }


    fun <T> doBaseHttp(
        preExec: suspend () -> Any?,
        exc: suspend () -> CommonResponse?,
        callback: OnRetrofitResultListener<T>,
        isCheckToken: Boolean = true
    ): Job? where T : BaseModel {
        return viewModelScope.launch {
            try {
                val t = preExec()
                if (t != null) {
                    return@launch
                }

                // 如果token不存在
                if (!isTokenAvailable() && isCheckToken) {
                    val token = getToken()
                    if (TextUtils.isEmpty(token)) {
                        callback.onFailed("用户身份已过期，请清空缓存后再尝试！")
                        return@launch
                    }
                }

                val result = exc()
                if (!isActive) return@launch
                if (result == null) {
                    callback.onFailed("用户身份已过期")
                    return@launch
                }

                if (result.code == 444 && isCheckToken) {
                    val token = getToken()
                    if (!isActive) return@launch
                    if (TextUtils.isEmpty(token)) {
                        callback.onFailed("用户身份已过期，请清空缓存后再尝试！")
                    } else {
                        doBaseHttp(exc, callback)
                    }
                    return@launch
                }

                if (TextUtils.isEmpty(result.ticket) || TextUtils.isEmpty(result.body)) {
                    if (!isActive) return@launch
                    callback.onFailed("")
                    return@launch
                }

                if (!isActive) return@launch
                // 用rsa的私钥去解密ticket，获得aes的秘钥
                val aesKey = EncryptionUtils.rsaDecrypt(result.ticket)
                if (aesKey == null) {
                    if (!isActive) return@launch
                    callback.onFailed("AppUtils.getString(R.string.error_net)")
                    return@launch
                }
                val jsonBody = EncryptionUtils.aesDecrypt(result.body, aesKey)
                if (jsonBody == null) {
                    if (!isActive) return@launch
                    callback.onFailed("")
                    return@launch
                }
                //这里获得到的是类的泛型的类型
                if (!isActive) return@launch
                val type = TypeUtils.getInterfaceT(callback, 0)
                if (type != null) {
                    val model = Gson().fromJson<T>(jsonBody, type)
                    if (model?.success == "false") {
                        val msg = model.msg ?: ""
                        callback.onFailed(msg)
                    }
                    callback.onSuccess(model)
                } else {
                    callback.onFailed("AppUtils.getString(R.string.error_net)")
                }
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
        }
    }

    fun <T> doBaseHttp(
        exc: suspend () -> CommonResponse?,
        callback: OnRetrofitResultListener<T>,
        isCheckToken: Boolean = true
    ) where T : BaseModel {
        doBaseHttp({
            withContext(Dispatchers.IO) {
                return@withContext null
            }
        }, exc, callback, isCheckToken)
    }


    open fun isTokenAvailable(): Boolean{
        if (TextUtils.isEmpty(SPUtil.instance.token)) return false
        val createTokenTime = SPUtil.instance.tokenExpireTime
        return  System.currentTimeMillis() < createTokenTime
    }

    fun isNotActive(): Boolean {
        return !viewModelScope.isActive
    }

    fun getCommonRequest(obj: Any): CommonRequest {
        val json = Gson().toJson(obj)
        val commonRequest = CommonRequest()
        commonRequest.body = EncryptionUtils.aesEncrypt(json)
        commonRequest.ticket = EncryptionUtils.rsaEncrypt()
        return commonRequest
    }



    fun <T> doBaseHttp(
        preExec: suspend () -> Any?,
        exc: suspend () -> T?,
        success: (T) -> Unit,
        fail: (errorMsg: String) -> Unit
    ): Job? where T : BaseModel {
        return viewModelScope.launch {
            try {
                val t = preExec()
                if (t != null) {
                    return@launch
                }
                val result = exc()
                if (!isActive) return@launch
                if (result == null) {
                    fail(result?.msg?:"")
                } else {
                    success(result)
                }
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
        }
    }

    fun <T> doBaseHttp(
        exc: suspend () -> T?,
        success: (T) -> Unit,
        fail: (errorMsg: String) -> Unit
    ) where T : BaseModel {
        doBaseHttp({
            withContext(Dispatchers.IO) {
                return@withContext null
            }
        }, exc, success, fail)
    }



    fun <T> doAsync(exe: suspend () -> T?, success: (t: T) -> Unit, fail: () -> Unit) {
        viewModelScope.launch {
            try {
                val result = withContext(Dispatchers.IO) {
                    exe()
                }
                if (isNotActive()) return@launch
                if (result == null) {
                    fail()
                } else {
                    success(result)
                }
            } catch (e: Exception) {
                e.printStackTrace()
                if (isNotActive()) return@launch
                fail()
            }
        }
    }


}